#include "CloudViewer.h"

CloudViewer::CloudViewer(QWidget *parent)
    : QMainWindow(parent), filtering_axis_(2), // = z
      color_mode_(4)                           // = Rainbow
{
    ui.setupUi(this);

    /***** Slots connection of QMenuBar and QToolBar *****/
    // File (connect)
    QObject::connect(ui.openAction, &QAction::triggered, this,
                     &CloudViewer::open);
    QObject::connect(ui.addAction, &QAction::triggered, this, &CloudViewer::add);
    QObject::connect(ui.clearAction, &QAction::triggered, this,
                     &CloudViewer::clear);

    ui.saveAction->setData(QVariant(false));      // isSaveBinary = false
    ui.saveBinaryAction->setData(QVariant(true)); // isSaveBinary = true
    connect(ui.saveAction, SIGNAL(triggered()), this, SLOT(save()));
    connect(ui.saveBinaryAction, SIGNAL(triggered()), this, SLOT(save()));
    QObject::connect(ui.exitAction, &QAction::triggered, this,
                     &CloudViewer::exit);
    // Display (connect)
    QObject::connect(ui.pointcolorAction, &QAction::triggered, this,
                     &CloudViewer::pointcolorChanged);
    QObject::connect(ui.bgcolorAction, &QAction::triggered, this,
                     &CloudViewer::bgcolorChanged);
    QObject::connect(ui.mainviewAction, &QAction::triggered, this,
                     &CloudViewer::mainview);
    QObject::connect(ui.leftviewAction, &QAction::triggered, this,
                     &CloudViewer::leftview);
    QObject::connect(ui.topviewAction, &QAction::triggered, this,
                     &CloudViewer::topview);
    QObject::connect(ui.resetviewAction, &QAction::triggered, this,
                     &CloudViewer::resetview);
    //鼠标框选点云
    QObject::connect(ui.actionSlectPtCloudPart, &QAction::triggered, this,
                     &CloudViewer::areaPicking);
    //检测划痕深度、宽度、长度
    QObject::connect(ui.actionScratchDetect, &QAction::triggered, this,
                     &CloudViewer::scratchDetection);
    //检测沟槽标准件的深度、宽度、长度
    QObject::connect(ui.actionGrooveDetect, &QAction::triggered, this,
                     &CloudViewer::grooveDetection);
    //平面拟合
    QObject::connect(ui.actionPlanFit, &QAction::triggered, this,
                     &CloudViewer::planFit);
    //计算高度差
    QObject::connect(ui.actionHeightDiff, &QAction::triggered, this,
                     &CloudViewer::heightDiff);
    //球面拟合
    QObject::connect(ui.actionSphereFit, &QAction::triggered, this,
                     &CloudViewer::sphereFit);

    // Option (connect)
    ui.windowsThemeAction->setData(QVariant(CLOUDVIEWER_THEME_WINDOWS));
    ui.darculaThemeAction->setData(QVariant(CLOUDVIEWER_THEME_DARCULA));
    ui.englishAction->setData(QVariant(CLOUDVIEWER_LANG_ENGLISH));
    ui.chineseAction->setData(QVariant(CLOUDVIEWER_LANG_CHINESE));
    connect(ui.windowsThemeAction, SIGNAL(triggered()), this,SLOT(changeTheme()));
    connect(ui.darculaThemeAction, SIGNAL(triggered()), this,
            SLOT(changeTheme()));
    connect(ui.englishAction, SIGNAL(triggered()), this, SLOT(changeLanguage()));
    connect(ui.chineseAction, SIGNAL(triggered()), this, SLOT(changeLanguage()));
    // About (connect)
    QObject::connect(ui.aboutAction, &QAction::triggered, this,
                     &CloudViewer::about);
    QObject::connect(ui.helpAction, &QAction::triggered, this,
                     &CloudViewer::help);

    /***** Connect X,Y,Z radio buttons and their
   * functions*************************/
    //选择以Ｘ，Ｙ，Ｚ方向添加点云颜色

    connect(ui.radioButton_x, SIGNAL(clicked()), this, SLOT(axisChosen()));
    connect(ui.radioButton_y, SIGNAL(clicked()), this, SLOT(axisChosen()));
    connect(ui.radioButton_z, SIGNAL(clicked()), this, SLOT(axisChosen()));

    connect(ui.radioButton_BlueRed, SIGNAL(clicked()), this,
            SLOT(lookUpTableChosen()));
    connect(ui.radioButton_GreenMagenta, SIGNAL(clicked()), this,
            SLOT(lookUpTableChosen()));
    connect(ui.radioButton_WhiteRed, SIGNAL(clicked()), this,
            SLOT(lookUpTableChosen()));
    connect(ui.radioButton_GreyRed, SIGNAL(clicked()), this,
            SLOT(lookUpTableChosen()));
    connect(ui.radioButton_Rainbow, SIGNAL(clicked()), this,
            SLOT(lookUpTableChosen()));

    // Change size of cloud (connect)
    connect(ui.pSlider, SIGNAL(valueChanged(int)), this,
            SLOT(pSliderChanged(int)));
    connect(ui.pSlider, SIGNAL(sliderReleased()), this, SLOT(psliderReleased()));
    // Checkbox for coordinate and background color (connect)
    connect(ui.cooCbx, SIGNAL(stateChanged(int)), this, SLOT(cooCbxChecked(int)));
    connect(ui.bgcCbx, SIGNAL(stateChanged(int)), this, SLOT(bgcCbxChecked(int)));

    /***** Slots connection of dataTree(QTreeWidget) widget *****/
    // Item in dataTree is left-clicked (connect)
    connect(ui.dataTree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this,
            SLOT(itemSelected(QTreeWidgetItem *, int)));
    // Item in dataTree is right-clicked
    connect(ui.dataTree, SIGNAL(customContextMenuRequested(const QPoint &)), this,
            SLOT(popMenu(const QPoint &)));

    connect(ui.consoleTable, SIGNAL(customContextMenuRequested(const QPoint &)),
            this, SLOT(popMenuInConsole(const QPoint &)));
    // Initialization
    initial();
}

CloudViewer::~CloudViewer() {}

void CloudViewer::doOpen(const QStringList &filePathList) {
    // Open point cloud file one by one
    for (int i = 0; i != filePathList.size(); i++) {
        timeStart();                          // time start
        mycloud.cloud.reset(new PointCloudT); // Reset cloud
        QFileInfo fileInfo(filePathList[i]);
        std::string filePath = fromQString(fileInfo.filePath());
        std::string fileName = fromQString(fileInfo.fileName());

        // begin loading
        ui.statusBar->showMessage(fileInfo.fileName() + ": " + QString::number(i) +
                                  "/" + QString::number(filePathList.size()) +
                                  " point cloud loading...");

        mycloud = fileIO.load(fileInfo);
        if (!mycloud.isValid) {
            // TODO: deal with the error, print error info in console?
            debug("invalid cloud.");
            continue;
        }
        mycloud.viewer = viewer_;
        mycloud_vec.push_back(mycloud);

        timeCostSecond = timeOff(); // time off

        consoleLog("Open", toQString(mycloud.fileName), toQString(mycloud.filePath),
                   "Time cost: " + timeCostSecond + " s, Points: " +
                   QString::number(mycloud.cloud->points.size()));

        // update tree widget
        QTreeWidgetItem *cloudName =
                new QTreeWidgetItem(QStringList() << toQString(mycloud.fileName));
        cloudName->setIcon(0, QIcon(":/Resources/images/icon.png"));
        ui.dataTree->addTopLevelItem(cloudName);

        total_points += mycloud.cloud->points.size();
    }
    ui.statusBar->showMessage("");
    colorCloudVecDistances();
    showPointcloudAdd();
    setPropertyTable();
}

// Open point cloud
void CloudViewer::open() {
    QStringList filePathList = QFileDialog::getOpenFileNames(
                this, tr("Open point cloud file"), toQString(mycloud.fileDir),
                toQString(fileIO.getInputFormatsStr()));
    if (filePathList.isEmpty())
        return;

    // Clear cache
    // TODO: abstract a function
    mycloud_vec.clear();
    total_points = 0;
    ui.dataTree->clear();
    viewer_->removeAllPointClouds();

    doOpen(filePathList);
}

// Add Point Cloud
void CloudViewer::add() {
    QStringList filePathList = QFileDialog::getOpenFileNames(
                this, tr("Add point cloud file"), toQString(mycloud.fileDir),
                toQString(fileIO.getInputFormatsStr()));
    if (filePathList.isEmpty())
        return;

    doOpen(filePathList);
}

// Clear all point clouds
void CloudViewer::clear() {
    mycloud_vec.clear();             //从点云容器中移除所有点云
    viewer_->removeAllPointClouds(); //从viewer中移除所有点云
    viewer_->removeAllShapes();      //这个remove更彻底
    ui.dataTree->clear();            //将dataTree清空

    ui.propertyTable->clear(); //清空属性窗口propertyTable
    QStringList header;
    header << "Property"
           << "Value";
    ui.propertyTable->setHorizontalHeaderLabels(header);

    //输出窗口
    consoleLog("Clear", "All point clouds", "", "");

    setWindowTitle("CloudProcess"); //更新窗口标题
    showPointcloud();              //更新显示
}

// Save point cloud
void CloudViewer::save() {
    if (!mycloud.isValid) {
        QMessageBox::critical(this, tr("Saving file error"),
                              tr("There is no point cloud to save"));
        return;
    }

    // get binary flag from sender()
    QAction *action = qobject_cast<QAction *>(sender());
    QVariant v = action->data();
    bool isSaveBinary = (bool)v.value<bool>();

    QString selectedFilter = toQString(fileIO.outputFiltersMap.at(mycloud.fileSuffix));
    QString saveFilePath = QFileDialog::getSaveFileName(
                this,                                    // parent
                toQString("Save point cloud" + string(isSaveBinary ? " (binary)": "")), // caption
                toQString(mycloud.filePath),             // dir
                toQString(fileIO.getOutputFormatsStr()), // filter
                &selectedFilter                          // selected filter
                );
    if (saveFilePath.isEmpty()) return;

    QFileInfo fileInfo(saveFilePath);
    QString saveFileName = fileInfo.fileName();
    string saveFilePathStd = fromQString(saveFilePath);
    string saveFileNameStd = fromQString(saveFileName);

    if (mycloud_vec.size() > 1) {
        savemulti(fileInfo, isSaveBinary);
        return;
    }

    bool saveStatus = fileIO.save(mycloud, fileInfo, isSaveBinary);
    if (!saveStatus) {
        QMessageBox::critical(this, tr("Saving file error"),
                              tr("We can not save the file"));
        return;
    }

    consoleLog("Save", saveFileName, saveFilePath, "Single save");

    setWindowTitle(saveFilePath + " - CloudViewer");
    QMessageBox::information(this, tr("save point cloud file"),
                             toQString("Save " + saveFileNameStd + " successfully!"));
}

// Save multi point cloud
void CloudViewer::savemulti(const QFileInfo &fileInfo, bool isSaveBinary) {
    string subname = fromQString(fileInfo.fileName());
    QString saveFilePath = fileInfo.filePath();
    PointCloudT::Ptr multi_cloud;
    multi_cloud.reset(new PointCloudT);
    multi_cloud->height = 1;
    int sum = 0;
    for (auto c : mycloud_vec) {
        sum += c.cloud->points.size();
    }
    multi_cloud->width = sum;
    multi_cloud->resize(multi_cloud->height * multi_cloud->width);
    int k = 0;
    for (int i = 0; i != mycloud_vec.size(); ++i) {
        // 注意cloudvec[i]->points.size()和cloudvec[i]->size()的区别
        for (int j = 0; j != mycloud_vec[i].cloud->points.size(); ++j) {
            multi_cloud->points[k].x = mycloud_vec[i].cloud->points[j].x;
            multi_cloud->points[k].y = mycloud_vec[i].cloud->points[j].y;
            multi_cloud->points[k].z = mycloud_vec[i].cloud->points[j].z;
            multi_cloud->points[k].r = mycloud_vec[i].cloud->points[j].r;
            multi_cloud->points[k].g = mycloud_vec[i].cloud->points[j].g;
            multi_cloud->points[k].b = mycloud_vec[i].cloud->points[j].b;
            k++;
        }
    }

    MyCloud multiMyCloud;
    multiMyCloud.cloud = multi_cloud;
    multiMyCloud.isValid = true;

    // save multi_cloud
    bool saveStatus = fileIO.save(multiMyCloud, fileInfo, isSaveBinary);
    if (!saveStatus) {
        QMessageBox::critical(this, tr("Saving file error"),
                              tr("We can not save the file"));
        return;
    }

    if (isSaveBinary) {
        consoleLog("Save as binary", QString::fromLocal8Bit(subname.c_str()),
                   saveFilePath, "Multi save (binary)");
    } else {
        consoleLog("Save", QString::fromLocal8Bit(subname.c_str()), saveFilePath,
                   "Multi save");
    }

    // 将保存后的 multi_cloud 设置为当前 mycloud,以便保存之后直接进行操作
    mycloud.cloud = multi_cloud;
    mycloud.filePath = fromQString(saveFilePath);
    mycloud.fileName = subname;

    setWindowTitle(saveFilePath + " - CloudViewer");
    QMessageBox::information(this, tr("save point cloud file"),
                             toQString("Save " + subname + " successfully!"));
}

//退出程序
void CloudViewer::exit() { this->close(); }

//初始化
void CloudViewer::initial() {
    //界面初始化
    setWindowIcon(QIcon(tr(":/Resources/images/icon.png")));
    setWindowTitle(tr("CloudProcess"));

    //点云初始化
    mycloud.cloud.reset(new PointCloudT);
    mycloud.cloud->resize(1);
    mycloudSelected.cloud.reset(new PointCloudT);
    mycloudSelected.cloud->resize(1);
    mycloudSelected.fileName = "selected";
    mycloudSelected.viewer = viewer_;
    mycloudSelected.cloudId = "selected";

    viewer_.reset(new pcl::visualization::PCLVisualizer("viewer", false));
    // viewer->addPointCloud(cloud, "cloud");

    ui.screen->SetRenderWindow(viewer_->getRenderWindow());
    viewer_->setupInteractor(ui.screen->GetInteractor(),
                             ui.screen->GetRenderWindow());
    ui.screen->update();

    ui.propertyTable->setSelectionMode(
                QAbstractItemView::NoSelection); // 禁止点击属性管理器的 item
    ui.consoleTable->setSelectionMode(
                QAbstractItemView::NoSelection); // 禁止点击输出窗口的 item
    ui.dataTree->setSelectionMode(
                QAbstractItemView::ExtendedSelection); // 允许 dataTree 进行多选

    // 设置默认主题
    QString qss = windows_qss;  //windows_qss;darcula_qss
    qApp->setStyleSheet(qss);

    setPropertyTable();
    setConsoleTable();

    // 输出窗口
    consoleLog("Software start", "CloudViewer", "Welcome to use CloudViewer", "");

    // 设置背景颜色为 dark
    viewer_->setBackgroundColor(30 / 255.0, 30 / 255.0, 30 / 255.0);
}

//显示点云，不重置相机角度
void CloudViewer::showPointcloud() {
    for (int i = 0; i != mycloud_vec.size(); i++) {
        viewer_->updatePointCloud(mycloud_vec[i].cloud, mycloud_vec[i].cloudId);
    }
    // viewer->resetCamera();
    ui.screen->update();
}

//添加点云到viewer,并显示点云
void CloudViewer::showPointcloudAdd() {
    for (int i = 0; i != mycloud_vec.size(); i++) {
        viewer_->addPointCloud(mycloud_vec[i].cloud, mycloud_vec[i].cloudId);
        viewer_->updatePointCloud(mycloud_vec[i].cloud, mycloud_vec[i].cloudId);
    }
    viewer_->resetCamera();
    ui.screen->update();
}
void CloudViewer::showPointcloudNew(int cloudPre_ID) {
    for (int i = cloudPre_ID + 1; i != mycloud_vec.size(); i++) {
        viewer_->addPointCloud(mycloud_vec[i].cloud, mycloud_vec[i].cloudId);
        viewer_->updatePointCloud(mycloud_vec[i].cloud, mycloud_vec[i].cloudId);
    }
    viewer_->resetCamera();
    ui.screen->update();
}

void CloudViewer::setCloudColor(unsigned int r, unsigned int g,
                                unsigned int b) {
    // Set the new color
    for (size_t i = 0; i < mycloud.cloud->size(); i++) {
        mycloud.cloud->points[i].r = r;
        mycloud.cloud->points[i].g = g;
        mycloud.cloud->points[i].b = b;
        mycloud.cloud->points[i].a = 255;
    }
}

//关于
void CloudViewer::about() {
    AboutWin *aboutwin = new AboutWin(this);
    aboutwin->setModal(true);
    aboutwin->show();
    consoleLog("About", "CloudProcess", "pointcloud process software",
               "Welcome to use!");
}

//帮助
void CloudViewer::help() {
    // QDesktopServices::openUrl(QUrl(QLatin1String("http://nightn.com/cloudviewer")));
    consoleLog("Help", "Cloudviewer help", "Not written", "");
}

// Change theme: Windows/Darcula
void CloudViewer::changeTheme() {
    QAction *action = qobject_cast<QAction *>(sender());
    QVariant v = action->data();
    int theme = (int)v.value<int>();

    QColor colorLight(241, 241, 241, 255);
    QColor colorDark(0, 0, 0, 255);
    QString qss;

    switch (theme) {
    case CLOUDVIEWER_THEME_WINDOWS: {
        qss = windows_qss;
        for (int i = 0; i != mycloud_vec.size(); i++) {
            if (ui.dataTree->topLevelItem(i)->textColor(0) == colorLight) {
                ui.dataTree->topLevelItem(i)->setTextColor(0, colorDark);
            }
        }
        theme_id = 0;
        consoleLog("Change theme", "Windows theme", "", "");
        break;
    }
    case CLOUDVIEWER_THEME_DARCULA: {
        qss = darcula_qss;
        for (int i = 0; i != mycloud_vec.size(); i++) {
            if (ui.dataTree->topLevelItem(i)->textColor(0) == colorDark) {
                ui.dataTree->topLevelItem(i)->setTextColor(0, colorLight);
            }
        }
        consoleLog("Change theme", "Darcula theme", "", "");
        theme_id = 1;
        break;
    }
    }
    qApp->setStyleSheet(qss);
}

// Change language: English/Chinese
void CloudViewer::changeLanguage() {
    QAction *action = qobject_cast<QAction *>(sender());
    QVariant v = action->data();
    int language = (int)v.value<int>();

    switch (language) {
    case CLOUDVIEWER_LANG_ENGLISH: {
        consoleLog("Change language", "English", "", "");
        break;
    }
    case CLOUDVIEWER_LANG_CHINESE: {
        consoleLog("Change language", "Chinese",
                   "Doesn't support Chinese temporarily", "");
        break;
    }
    }
}

/*********************************************/
/*****************界面槽函数*****************/
/********************************************/
void CloudViewer::colorBtnPressed() {
    QList<QTreeWidgetItem *> itemList = ui.dataTree->selectedItems();
    int selected_item_count = ui.dataTree->selectedItems().size();
    // 如果未选中任何点云，则对视图窗口中的所有点云进行着色
    if (selected_item_count == 0) {
        for (int i = 0; i != mycloud_vec.size(); i++) {
            for (int j = 0; j != mycloud_vec[i].cloud->points.size(); j++) {
                mycloud_vec[i].cloud->points[j].r =
                        255 * (1024 * rand() / (RAND_MAX + 1.0f));
                mycloud_vec[i].cloud->points[j].g =
                        255 * (1024 * rand() / (RAND_MAX + 1.0f));
                mycloud_vec[i].cloud->points[j].b =
                        255 * (1024 * rand() / (RAND_MAX + 1.0f));
            }
        }

        // 输出窗口
        consoleLog("Random color", "All point clous", "", "");

    } else {
        for (int i = 0; i != selected_item_count; i++) {
            int cloud_id = ui.dataTree->indexOfTopLevelItem(itemList[i]);
            for (int j = 0; j != mycloud_vec[cloud_id].cloud->size(); j++) {
                mycloud_vec[cloud_id].cloud->points[j].r = red;
                mycloud_vec[cloud_id].cloud->points[j].g =
                        255 * (1024 * rand() / (RAND_MAX + 1.0f));
                mycloud_vec[cloud_id].cloud->points[j].b =
                        255 * (1024 * rand() / (RAND_MAX + 1.0f));
            }
        }

        // 输出窗口
        consoleLog("Random color", "Point clouds selected", "", "");
    }
    showPointcloud();
}

void CloudViewer::RGBsliderReleased() {
    QList<QTreeWidgetItem *> itemList = ui.dataTree->selectedItems();
    int selected_item_count = ui.dataTree->selectedItems().size();
    // 如果未选中任何点云，则对视图窗口中的所有点云进行着色
    if (selected_item_count == 0) {
        for (int i = 0; i != mycloud_vec.size(); i++) {
            mycloud_vec[i].setPointColor(red, green, blue);
        }

        // 输出窗口
        consoleLog("Change cloud color", "All point clouds",
                   QString::number(red) + " " + QString::number(green) + " " +
                   QString::number(blue),
                   "");
    } else {
        for (int i = 0; i != selected_item_count; i++) {
            int cloud_id = ui.dataTree->indexOfTopLevelItem(itemList[i]);
            mycloud_vec[cloud_id].setPointColor(red, green, blue);
        }
        // 输出窗口
        consoleLog("Change cloud color", "Point clouds selected",
                   QString::number(red) + " " + QString::number(green) + " " +
                   QString::number(blue),
                   "");
    }
    showPointcloud();
}

//设置所有点云的尺寸
void CloudViewer::psliderReleased() {
    QList<QTreeWidgetItem *> itemList = ui.dataTree->selectedItems();
    int selected_item_count = ui.dataTree->selectedItems().size();
    if (selected_item_count == 0) {
        for (int i = 0; i != mycloud_vec.size(); i++) {
            viewer_->setPointCloudRenderingProperties(
                        pcl::visualization::PCL_VISUALIZER_POINT_SIZE, p,
                        mycloud_vec[i].cloudId);
        }
        // 输出窗口
        consoleLog("Change cloud size", "All point clouds",
                   "Size: " + QString::number(p), "");
    } else {
        for (int i = 0; i != selected_item_count; i++) {
            int cloud_id = ui.dataTree->indexOfTopLevelItem(itemList[i]);
            viewer_->setPointCloudRenderingProperties(
                        pcl::visualization::PCL_VISUALIZER_POINT_SIZE, p,
                        mycloud_vec[i].cloudId);
        }
        // 输出窗口
        consoleLog("Change cloud size", "Point clouds selected",
                   "Size: " + QString::number(p), "");
    }
    ui.screen->update();
}

void CloudViewer::pSliderChanged(int value) {
    p = value;
    ui.sizeLCD->display(value);
}

void CloudViewer::cooCbxChecked(int value) {
    switch (value) {
    case 0: {
        viewer_->removeCoordinateSystem();
        consoleLog("Remove coordinate system", "Remove", "", "");
        break;
    }
    case 2: {
        viewer_->addCoordinateSystem();
        consoleLog("Add coordinate system", "Add", "", "");
        break;
    }
    }
    ui.screen->update();
}

void CloudViewer::bgcCbxChecked(int value) {
    switch (value) {
    case 0: {
        viewer_->setBackgroundColor(30 / 255.0, 30 / 255.0, 30 / 255.0);
        consoleLog("Change bg color", "Background", "30 30 30", "");
        break;
    }
    case 2: {
        //！注意：setBackgroundColor()接收的是0-1的double型参数
        viewer_->setBackgroundColor(240 / 255.0, 240 / 255.0, 240 / 255.0);
        consoleLog("Change bg color", "Background", "240 240 240", "");
        break;
    }
    }
    ui.screen->update();
}

// 通过颜色对话框改变点云颜色
void CloudViewer::pointcolorChanged() {
    QColor color =
            QColorDialog::getColor(Qt::white, this, "Select color for point cloud");

    if (color.isValid()) {
        // QAction* action = dynamic_cast<QAction*>(sender());
        // if (action != ui.pointcolorAction) //改变颜色的信号来自于 dataTree
        QList<QTreeWidgetItem *> itemList = ui.dataTree->selectedItems();
        int selected_item_count = ui.dataTree->selectedItems().size();
        if (selected_item_count == 0) {
            for (int i = 0; i != mycloud_vec.size(); ++i) {
                mycloud_vec[i].setPointColor(color.red(), color.green(), color.blue());
            }
            // 输出窗口
            consoleLog("Change cloud color", "All point clouds",
                       QString::number(color.red()) + " " +
                       QString::number(color.green()) + " " +
                       QString::number(color.blue()),
                       "");
        } else {
            for (int i = 0; i != selected_item_count; i++) {
                int cloud_id = ui.dataTree->indexOfTopLevelItem(itemList[i]);
                mycloud_vec[cloud_id].setPointColor(color.red(), color.green(),
                                                    color.blue());
            }
            // 输出窗口
            consoleLog("Change cloud color", "Point clouds selected",
                       QString::number(color.red()) + " " +
                       QString::number(color.green()) + " " +
                       QString::number(color.blue()),
                       "");
        }
        //颜色的改变同步至RGB停靠窗口
        //        ui.rSlider->setValue(color.red());
        //        ui.gSlider->setValue(color.green());
        //        ui.bSlider->setValue(color.blue());

        showPointcloud();
    }
}

//通过颜色对话框改变背景颜色
void CloudViewer::bgcolorChanged() {
    QColor color =
            QColorDialog::getColor(Qt::white, this, "Select color for Background");
    if (color.isValid()) {
        viewer_->setBackgroundColor(color.red() / 255.0, color.green() / 255.0,
                                    color.blue() / 255.0);
        // 输出窗口
        consoleLog("Change bg color", "Background",
                   QString::number(color.red()) + " " +
                   QString::number(color.green()) + " " +
                   QString::number(color.blue()),
                   "");
        showPointcloud();
    }
}

//三视图
void CloudViewer::mainview() {
    viewer_->setCameraPosition(0, -1, 0, 0.5, 0.5, 0.5, 0, 0, 1);
    ui.screen->update();
}

void CloudViewer::leftview() {
    viewer_->setCameraPosition(-1, 0, 0, 0, 0, 0, 0, 0, 1);
    ui.screen->update();
}

void CloudViewer::topview() {
    viewer_->setCameraPosition(0, 0, 1, 0, 0, 0, 0, 1, 0);
    ui.screen->update();
}
//重置视图
void CloudViewer::resetview() {
    viewer_->resetCamera();
    ui.screen->update();
}

// 设置属性管理窗口
void CloudViewer::setPropertyTable() {
    QStringList header;
    header << "Property"
           << "Value";
    ui.propertyTable->setHorizontalHeaderLabels(header);
    ui.propertyTable->setItem(0, 0, new QTableWidgetItem("Clouds"));
    ui.propertyTable->setItem(
                0, 1, new QTableWidgetItem(QString::number(mycloud_vec.size())));

    ui.propertyTable->setItem(1, 0, new QTableWidgetItem("Points"));
    ui.propertyTable->setItem(1, 1, new QTableWidgetItem(""));

    ui.propertyTable->setItem(2, 0, new QTableWidgetItem("Total points"));
    ui.propertyTable->setItem(
                2, 1, new QTableWidgetItem(QString::number(total_points)));

    ui.propertyTable->setItem(3, 0, new QTableWidgetItem("RGB"));
    ui.propertyTable->setItem(3, 1, new QTableWidgetItem(""));

    ui.propertyTable->setItem(4, 0, new QTableWidgetItem("Plane coefficients"));
    ui.propertyTable->setItem(4, 1, new QTableWidgetItem(""));
}

void CloudViewer::setConsoleTable() {
    // 设置输出窗口
    QStringList header2;
    header2 << "Time"
            << "Operation"
            << "Operation object"
            << "Details"
            << "Note";
    ui.consoleTable->setHorizontalHeaderLabels(header2);
    ui.consoleTable->setColumnWidth(0, 150);
    ui.consoleTable->setColumnWidth(1, 200);
    ui.consoleTable->setColumnWidth(2, 200);
    ui.consoleTable->setColumnWidth(3, 300);

    // ui.consoleTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
    // //设置不可编辑
    ui.consoleTable->verticalHeader()->setDefaultSectionSize(22); //设置行距

    ui.consoleTable->setContextMenuPolicy(Qt::CustomContextMenu);
}

void CloudViewer::consoleLog(QString operation, QString subname,
                             QString filename, QString note) {
    if (enable_console == false) {
        return;
    }
    int rows = ui.consoleTable->rowCount();
    ui.consoleTable->setRowCount(++rows);
    QDateTime time = QDateTime::currentDateTime(); //获取系统现在的时间
    QString time_str = time.toString("MM-dd hh:mm:ss"); //设置显示格式
    ui.consoleTable->setItem(rows - 1, 0, new QTableWidgetItem(time_str));
    ui.consoleTable->setItem(rows - 1, 1, new QTableWidgetItem(operation));
    ui.consoleTable->setItem(rows - 1, 2, new QTableWidgetItem(subname));
    ui.consoleTable->setItem(rows - 1, 3, new QTableWidgetItem(filename));
    ui.consoleTable->setItem(rows - 1, 4, new QTableWidgetItem(note));

    ui.consoleTable->scrollToBottom(); // 滑动自动滚到最底部
}

// QTreeWidget的item的点击相应函数
void CloudViewer::itemSelected(QTreeWidgetItem *item, int count) {
    count = ui.dataTree->indexOfTopLevelItem(item); //获取item的行号

    for (int i = 0; i != mycloud_vec.size(); i++) {
        viewer_->updatePointCloud(mycloud_vec[i].cloud, mycloud_vec[i].cloudId);
        viewer_->setPointCloudRenderingProperties(
                    pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1,
                    mycloud_vec[i].cloudId);
    }

    //提取当前点云的RGB,点云数量等信息
    int cloud_size = mycloud_vec[count].cloud->points.size();
    unsigned int cloud_r = mycloud_vec[count].cloud->points[0].r;
    unsigned int cloud_g = mycloud_vec[count].cloud->points[0].g;
    unsigned int cloud_b = mycloud_vec[count].cloud->points[0].b;
    bool multi_color = true;
    if (mycloud_vec[count].cloud->points.begin()->r ==
            (mycloud_vec[count].cloud->points.end() - 1)
            ->r) //判断点云单色多色的条件（不是很严谨）
        multi_color = false;

    //提取当前点云的平面参数信息
    float cloud_plane_A = mycloud_vec[count].plane_A;
    float cloud_plane_B = mycloud_vec[count].plane_B;
    float cloud_plane_C = mycloud_vec[count].plane_C;
    float cloud_plane_D = mycloud_vec[count].plane_D;

    ui.propertyTable->setItem(
                0, 1, new QTableWidgetItem(QString::number(mycloud_vec.size())));
    ui.propertyTable->setItem(1, 1,
                              new QTableWidgetItem(QString::number(cloud_size)));
    ui.propertyTable->setItem(
                2, 1, new QTableWidgetItem(QString::number(total_points)));
    ui.propertyTable->setItem(
                3, 1,
                new QTableWidgetItem(multi_color ? "Multi Color"
                                                 : (QString::number(cloud_r) + " " +
                                                    QString::number(cloud_g) + " " +
                                                    QString::number(cloud_b))));
    ui.propertyTable->setItem(
                4, 1,
                new QTableWidgetItem(QString::number(cloud_plane_A) + " " +
                                     QString::number(cloud_plane_B) + " " +
                                     QString::number(cloud_plane_C)+ " " +
                                     QString::number(cloud_plane_D)));

    //选中item所对应的点云尺寸变大
    QList<QTreeWidgetItem *> itemList = ui.dataTree->selectedItems();
    int selected_item_count = ui.dataTree->selectedItems().size();
    for (int i = 0; i != selected_item_count; i++) {
        int cloud_id = ui.dataTree->indexOfTopLevelItem(itemList[i]);
        viewer_->setPointCloudRenderingProperties(
                    pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2,
                    mycloud_vec[i].cloudId);
    }
    // mycloud = mycloud_vec[count];
    ui.screen->update();
}

// consoleTable 右击响应事件
void CloudViewer::popMenuInConsole(const QPoint &) {
    QAction clearConsoleAction("Clear console", this);
    QAction enableConsoleAction("Enable console", this);
    QAction disableConsoleAction("Disable console", this);

    connect(&clearConsoleAction, &QAction::triggered, this,
            &CloudViewer::clearConsole);
    connect(&enableConsoleAction, &QAction::triggered, this,
            &CloudViewer::enableConsole);
    connect(&disableConsoleAction, &QAction::triggered, this,
            &CloudViewer::disableConsole);

    QPoint pos;
    QMenu menu(ui.dataTree);
    menu.addAction(&clearConsoleAction);
    menu.addAction(&enableConsoleAction);
    menu.addAction(&disableConsoleAction);

    if (enable_console == true) {
        menu.actions()[1]->setVisible(false);
        menu.actions()[2]->setVisible(true);
    } else {
        menu.actions()[1]->setVisible(true);
        menu.actions()[2]->setVisible(false);
    }

    menu.exec(QCursor::pos()); //在当前鼠标位置显示
}

// 清空 consoleTable
void CloudViewer::clearConsole() {
    ui.consoleTable->clearContents();
    ui.consoleTable->setRowCount(0);
}

// 允许使用 consoleTable
void CloudViewer::enableConsole() { enable_console = true; }

// 禁用 consoleTable
void CloudViewer::disableConsole() {
    clearConsole();
    enable_console = false;
}

// QTreeWidget的item的右击响应函数
void CloudViewer::popMenu(const QPoint &) {
    QTreeWidgetItem *curItem = ui.dataTree->currentItem(); //获取当前被点击的节点
    if (curItem == NULL)
        return; //这种情况是右键的位置不在treeItem的范围内，即在空白位置右击
    QString name = curItem->text(0);
    int id = ui.dataTree->indexOfTopLevelItem(curItem);
    MyCloud &myCloud = mycloud_vec[id];

    QAction hideItemAction("Hide", this);
    QAction showItemAction("Show", this);
    QAction deleteItemAction("Delete", this);
    QAction changeColorAction("Change color", this);
    // show mode
    QAction pointModeAction("Set point mode", this);
    QAction meshModeAction("Set mesh mode", this);
    QAction pointMeshModeAction("Set point+mesh mode", this);
    pointModeAction.setData(QVariant(CLOUDVIEWER_MODE_POINT));
    meshModeAction.setData(QVariant(CLOUDVIEWER_MODE_MESH));
    pointMeshModeAction.setData(QVariant(CLOUDVIEWER_MODE_POINT_MESH));

    pointModeAction.setCheckable(true);
    meshModeAction.setCheckable(true);
    pointMeshModeAction.setCheckable(true);

    if (myCloud.curMode == "point") {
        pointModeAction.setChecked(true);
    } else if (myCloud.curMode == "mesh") {
        meshModeAction.setChecked(true);
    } else if (myCloud.curMode == "point+mesh") {
        pointMeshModeAction.setChecked(true);
    }

    connect(&hideItemAction, &QAction::triggered, this, &CloudViewer::hideItem);
    connect(&showItemAction, &QAction::triggered, this, &CloudViewer::showItem);
    connect(&deleteItemAction, &QAction::triggered, this,
            &CloudViewer::deleteItem);
    connect(&changeColorAction, &QAction::triggered, this,
            &CloudViewer::pointcolorChanged);

    connect(&pointModeAction, SIGNAL(triggered()), this,
            SLOT(setRenderingMode()));
    connect(&meshModeAction, SIGNAL(triggered()), this, SLOT(setRenderingMode()));
    connect(&pointMeshModeAction, SIGNAL(triggered()), this,
            SLOT(setRenderingMode()));

    QPoint pos;
    QMenu menu(ui.dataTree);
    menu.addAction(&hideItemAction);
    menu.addAction(&showItemAction);
    menu.addAction(&deleteItemAction);
    menu.addAction(&changeColorAction);

    menu.addAction(&pointModeAction);
    menu.addAction(&meshModeAction);
    menu.addAction(&pointMeshModeAction);

    if (mycloud_vec[id].visible == true) {
        menu.actions()[1]->setVisible(false);
        menu.actions()[0]->setVisible(true);
    } else {
        menu.actions()[1]->setVisible(true);
        menu.actions()[0]->setVisible(false);
    }

    const vector<string> modes = myCloud.supportedModes;
    if (std::find(modes.begin(), modes.end(), "point") == modes.end()) {
        menu.actions()[4]->setVisible(false);
    }
    if (std::find(modes.begin(), modes.end(), "mesh") == modes.end()) {
        menu.actions()[5]->setVisible(false);
    }
    if (std::find(modes.begin(), modes.end(), "point+mesh") == modes.end()) {
        menu.actions()[6]->setVisible(false);
    }

    menu.exec(QCursor::pos()); //在当前鼠标位置显示
}
void CloudViewer::hideItem() {
    QList<QTreeWidgetItem *> itemList = ui.dataTree->selectedItems();
    for (int i = 0; i != ui.dataTree->selectedItems().size(); i++) {
        // TODO hide之后，item变成灰色，再次右击item时，“hideItem” 选项变成
        // “showItem” QTreeWidgetItem* curItem = ui.dataTree->currentItem();
        QTreeWidgetItem *curItem = itemList[i];
        QString name = curItem->text(0);
        int id = ui.dataTree->indexOfTopLevelItem(curItem);
        mycloud_vec[id].hide();
        // QMessageBox::information(this, "cloud_id",
        // QString::fromLocal8Bit(cloud_id.c_str()));

        QColor item_color = QColor(112, 122, 132, 255);
        curItem->setTextColor(0, item_color);
        mycloud_vec[id].visible = false;
    }

    // 输出窗口
    consoleLog("Hide point clouds", "Point clouds selected", "", "");

    ui.screen->update(); //刷新视图窗口，不能省略
}

void CloudViewer::showItem() {
    QList<QTreeWidgetItem *> itemList = ui.dataTree->selectedItems();
    for (int i = 0; i != ui.dataTree->selectedItems().size(); i++) {
        // QTreeWidgetItem* curItem = ui.dataTree->currentItem();
        QTreeWidgetItem *curItem = itemList[i];
        QString name = curItem->text(0);
        int id = ui.dataTree->indexOfTopLevelItem(curItem);
        // 将cloud_id所对应的点云设置成透明
        mycloud_vec[id].show();
        QColor item_color;
        if (theme_id == 0) {
            item_color = QColor(0, 0, 0, 255);
        } else {
            item_color = QColor(241, 241, 241, 255);
        }
        curItem->setTextColor(0, item_color);
        mycloud_vec[id].visible = true;
    }

    // 输出窗口
    consoleLog("Show point clouds", "Point clouds selected", "", "");

    ui.screen->update(); //刷新视图窗口，不能省略
}

void CloudViewer::deleteItem() {
    QList<QTreeWidgetItem *> itemList = ui.dataTree->selectedItems();
    // ui.dataTree->selectedItems().size()
    // 随着迭代次数而改变，因此循环条件要设置为固定大小的 selected_item_count
    int selected_item_count = ui.dataTree->selectedItems().size();
    for (int i = 0; i != selected_item_count; i++) {
        // QTreeWidgetItem* curItem = ui.dataTree->currentItem();
        // QMessageBox::information(this, "itemList's size",
        // QString::number(ui.dataTree->selectedItems().size()));
        QTreeWidgetItem *curItem = itemList[i];
        QString name = curItem->text(0);
        int id = ui.dataTree->indexOfTopLevelItem(curItem);
        // QMessageBox::information(this, "information", "curItem: " + name + " " +
        // QString::number(id));
        auto it = mycloud_vec.begin() + ui.dataTree->indexOfTopLevelItem(curItem);
        // 删除点云之前，将其点的数目保存
        int delete_points = (*it).cloud->points.size();
        it = mycloud_vec.erase(it);
        // QMessageBox::information(this, "information",
        // QString::number(delete_points) + " " +
        // QString::number(mycloud_vec.size()));

        total_points -= delete_points;
        setPropertyTable();

        ui.dataTree->takeTopLevelItem(ui.dataTree->indexOfTopLevelItem(curItem));
    }

    // 移除之后再添加，避免 id 和资源管理树行号不一致的情况
    viewer_->removeAllPointClouds();
    for (int i = 0; i != mycloud_vec.size(); i++) {
        viewer_->addPointCloud(mycloud_vec[i].cloud, mycloud_vec[i].cloudId);
        viewer_->updatePointCloud(mycloud_vec[i].cloud, mycloud_vec[i].cloudId);
    }

    // 输出窗口
    consoleLog("Delete point clouds", "Point clouds selected", "", "");

    ui.screen->update();
}

void CloudViewer::setRenderingMode() {
    QAction *action = qobject_cast<QAction *>(sender());
    QVariant v = action->data();
    int mode = (int)v.value<int>();
    string modeStr;

    switch (mode) {
    case CLOUDVIEWER_MODE_POINT: {
        modeStr = "point";
        consoleLog("Point Mode", "Point clouds selected", "", "");
        break;
    }
    case CLOUDVIEWER_MODE_MESH: {
        modeStr = "mesh";
        consoleLog("Mesh Mode", "Point clouds selected", "", "");
        break;
    }
    case CLOUDVIEWER_MODE_POINT_MESH: {
        modeStr = "point+mesh";
        consoleLog("Point+Mesh Mode", "Point clouds selected", "", "");
        break;
    }
    }

    QList<QTreeWidgetItem *> itemList = ui.dataTree->selectedItems();
    for (int i = 0; i != ui.dataTree->selectedItems().size(); i++) {
        QTreeWidgetItem *curItem = itemList[i];
        QString name = curItem->text(0);
        int id = ui.dataTree->indexOfTopLevelItem(curItem);
        MyCloud &myCloud = mycloud_vec[id];
        myCloud.setShowMode(modeStr);
    }
    ui.screen->update();
}

void CloudViewer::debug(const string &s) {
    QMessageBox::information(this, tr("Debug"),
                             QString::fromLocal8Bit(s.c_str()));
}

void CloudViewer::axisChosen() {
    // Only 1 of the button can be checked at the time (mutual exclusivity) in a
    // group of radio buttons
    if (ui.radioButton_x->isChecked()) {
        PCL_INFO("x filtering chosen\n");
        filtering_axis_ = 0;
    } else if (ui.radioButton_y->isChecked()) {
        PCL_INFO("y filtering chosen\n");
        filtering_axis_ = 1;
    } else {
        PCL_INFO("z filtering chosen\n");
        filtering_axis_ = 2;
    }

    colorCloudVecDistances();
    showPointcloud();
}

void CloudViewer::lookUpTableChosen() {
    // Only 1 of the button can be checked at the time (mutual exclusivity) in a
    // group of radio buttons
    if (ui.radioButton_BlueRed->isChecked()) {
        PCL_INFO("Blue -> Red LUT chosen\n");
        color_mode_ = 0;
    } else if (ui.radioButton_GreenMagenta->isChecked()) {
        PCL_INFO("Green -> Magenta LUT chosen\n");
        color_mode_ = 1;
    } else if (ui.radioButton_WhiteRed->isChecked()) {
        PCL_INFO("White -> Red LUT chosen\n");
        color_mode_ = 2;
    } else if (ui.radioButton_GreyRed->isChecked()) {
        PCL_INFO("Grey / Red LUT chosen\n");
        color_mode_ = 3;
    } else {
        PCL_INFO("Rainbow LUT chosen\n");
        color_mode_ = 4;
    }

    colorCloudVecDistances();
    showPointcloud();
}

void CloudViewer::colorCloudVecDistances() {
    QList<QTreeWidgetItem *> itemList = ui.dataTree->selectedItems();
    int selected_item_count = ui.dataTree->selectedItems().size();
    // 如果未选中任何点云，则对视图窗口中的所有点云进行着色
    if (selected_item_count == 0) {
        for (int i = 0; i != mycloud_vec.size(); i++) {
            int cloud_id = i;
            colorCloudDist(cloud_id);
        }

        // 输出窗口
        consoleLog("Color on axis", "All point clous", "", "");

    } else {
        for (int i = 0; i != selected_item_count; i++) {
            int cloud_id = ui.dataTree->indexOfTopLevelItem(itemList[i]);
            colorCloudDist(cloud_id);
        }

        // 输出窗口
        consoleLog("Color on axis", "Point clouds selected", "", "");
    }
}

void CloudViewer::colorCloudDist(int cloud_id) {

    // Find the minimum and maximum values along the selected axis
    double min, max;
    // Set an initial value
    switch (filtering_axis_) {
    case 0: // x
        min = mycloud_vec[cloud_id].cloud->points[0].x;
        max = mycloud_vec[cloud_id].cloud->points[0].x;
        break;
    case 1: // y
        min = mycloud_vec[cloud_id].cloud->points[0].y;
        max = mycloud_vec[cloud_id].cloud->points[0].y;
        break;
    default: // z
        min = mycloud_vec[cloud_id].cloud->points[0].z;
        max = mycloud_vec[cloud_id].cloud->points[0].z;
        break;
    }

    // Search for the minimum/maximum
    for (PointCloudT::iterator cloud_it = mycloud_vec[cloud_id].cloud->begin();
         cloud_it != mycloud_vec[cloud_id].cloud->end(); ++cloud_it) {
        switch (filtering_axis_) {
        case 0: // x
            if (min > cloud_it->x)
                min = cloud_it->x;

            if (max < cloud_it->x)
                max = cloud_it->x;
            break;
        case 1: // y
            if (min > cloud_it->y)
                min = cloud_it->y;

            if (max < cloud_it->y)
                max = cloud_it->y;
            break;
        default: // z
            if (min > cloud_it->z)
                min = cloud_it->z;

            if (max < cloud_it->z)
                max = cloud_it->z;
            break;
        }
    }

    // Compute LUT scaling to fit the full histogram spectrum
    double lut_scale = 255.0 / (max - min); // max is 255, min is 0

    if (min ==
            max) // In case the cloud is flat on the chosen direction (x,y or z)
        lut_scale = 1.0; // Avoid rounding error in boost

    for (PointCloudT::iterator cloud_it = mycloud_vec[cloud_id].cloud->begin();
         cloud_it != mycloud_vec[cloud_id].cloud->end(); ++cloud_it) {
        int value;
        switch (filtering_axis_) {
        case 0: // x
            value = boost::math::iround(
                        (cloud_it->x - min) *
                        lut_scale); // Round the number to the closest integer
            break;
        case 1: // y
            value = boost::math::iround((cloud_it->y - min) * lut_scale);
            break;
        default: // z
            value = boost::math::iround((cloud_it->z - min) * lut_scale);
            break;
        }

        // Apply color to the cloud
        switch (color_mode_) {
        case 0:
            // Blue (= min) -> Red (= max)
            cloud_it->r = value;
            cloud_it->g = 0;
            cloud_it->b = 255 - value;
            break;
        case 1:
            // Green (= min) -> Magenta (= max)
            cloud_it->r = value;
            cloud_it->g = 255 - value;
            cloud_it->b = value;
            break;
        case 2:
            // White (= min) -> Red (= max)
            cloud_it->r = 255;
            cloud_it->g = 255 - value;
            cloud_it->b = 255 - value;
            break;
        case 3:
            // Grey (< 128) / Red (> 128)
            if (value > 128) {
                cloud_it->r = 255;
                cloud_it->g = 0;
                cloud_it->b = 0;
            } else {
                cloud_it->r = 128;
                cloud_it->g = 128;
                cloud_it->b = 128;
            }
            break;
        default:
            // Blue -> Green -> Red (~ rainbow)
            cloud_it->r =
                    value > 128 ? (value - 128) * 2 : 0; // r[128] = 0, r[255] = 255
            cloud_it->g =
                    value < 128
                    ? 2 * value
                    : 255 - ((value - 128) * 2); // g[0] = 0, g[128] = 255, g[255] = 0
            cloud_it->b =
                    value < 128 ? 255 - (2 * value) : 0; // b[0] = 255, b[128] = 0
        }
    }
}

//框选事件的回调
int CloudViewer::areaPicking() {

    QList<QTreeWidgetItem *> itemList = ui.dataTree->selectedItems();
    int selected_item_count = ui.dataTree->selectedItems().size();
    // 如果未选中任何点云
    if (selected_item_count == 0) {
        // 错误提示：没有选择点云文件
        QMessageBox::critical(this, tr("Select a part of pointcloud with mouse."),
                              tr("There is no Pointcloud file selected."));
        return -1;

    }

    else if (selected_item_count == 1) {

        cloudselect_id = ui.dataTree->indexOfTopLevelItem(itemList[0]);

        //若该点云没有被框选过，则计数值归零，否则增加计数
        if(!mycloud_vec[cloudselect_id].is_seleted) selected_num=0;
        else selected_num++;

        pcl::PointXYZRGB point;
        pcl::PointCloud<pcl::PointXYZRGB>::Ptr rgbCloudSelect(new pcl::PointCloud<pcl::PointXYZRGB>);
        //按坐标轴赋颜色
        colorCloudVecDistances();

        for (size_t i = 0; i < mycloud_vec[cloudselect_id].cloud->size(); i++) {
            point.x = mycloud_vec[cloudselect_id].cloud->points[i].x;
            point.y = mycloud_vec[cloudselect_id].cloud->points[i].y;
            point.z = mycloud_vec[cloudselect_id].cloud->points[i].z;
            point.r = mycloud_vec[cloudselect_id].cloud->points[i].r;
            point.g = mycloud_vec[cloudselect_id].cloud->points[i].g;
            point.b = mycloud_vec[cloudselect_id].cloud->points[i].b;
            rgbCloudSelect->push_back(point);
        }
        if (!rgbCloudSelect) {
            return -1;
        }
        //更新框选状态
        mycloud_vec[cloudselect_id].is_seleted = true;

        // 输出窗口
        consoleLog("SelectPointCloudPart",
                   toQString(mycloud_vec[cloudselect_id].fileName),
                   toQString(mycloud_vec[cloudselect_id].filePath),
                   "press 'X' to strat or ending picking");

        ui.statusBar->showMessage("");


        //框选类

        PtPicking dc(rgbCloudSelect);
        dc.areaPicking();  //调用区域选择类
        dc.spin();

        mycloudSelected.cloud.reset(new PointCloudT);

        //将框选结果复制给mycloudSelected
        pcl::copyPointCloud(*dc.clicked_points_3d, *mycloudSelected.cloud);

        //根据计数值给新增的框选点云编号
        stringstream ss;
        ss << mycloud_vec[cloudselect_id].fileName << "-selected-" << selected_num;

        mycloudSelected.fileName = ss.str();
        mycloudSelected.viewer = viewer_;
        mycloudSelected.cloudId = "cloud-" + mycloudSelected.fileName;
        //mycloudSelected.isValid = true;
        mycloudSelected.setPointColor(255, 255, 255); // red

        mycloud_vec.push_back(mycloudSelected);

        //更新点云可视化窗口
        viewer_->addPointCloud(mycloud_vec.back().cloud, mycloud_vec.back().cloudId);

        viewer_->setPointCloudRenderingProperties(
                    pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2,
                    mycloud_vec.back().cloudId);
        viewer_->updatePointCloud(mycloud_vec.back().cloud, mycloud_vec.back().cloudId);
        ui.screen->update();

        // update tree widget
        QTreeWidgetItem *cloudName = new QTreeWidgetItem(
                    QStringList() << toQString(mycloudSelected.fileName));
        cloudName->setIcon(0, QIcon(":/Resources/images/icon.png"));
        ui.dataTree->addTopLevelItem(cloudName);

        total_points += mycloud.cloud->points.size();
        setPropertyTable();

    } else {
        //错误提示：只能选择一个点云文件
        QMessageBox::critical(this, tr("Select a part of pointcloud with mouse."),
                              tr("You can just select one Pointcloud file."));
        return -1;
    }
    return 0;
}

int CloudViewer::grooveDetection() {
    QList<QTreeWidgetItem *> itemList = ui.dataTree->selectedItems();
    int selected_item_count = ui.dataTree->selectedItems().size();
    // 如果未选中任何点云，则对视图窗口中的所有点云进行着色
    if (selected_item_count == 0) {
        // 错误提示：没有选择点云文件
        QMessageBox::critical(this, tr("Select a part of pointcloud with mouse."),
                              tr("There is no Pointcloud file selected."));
        return -1;

    } else if (selected_item_count == 1) {

        int cloud_id = ui.dataTree->indexOfTopLevelItem(itemList[0]);
        pcl::PointXYZ point;
        xyzCloud.reset(new pcl::PointCloud<pcl::PointXYZ>);
        for (size_t i = 0; i < mycloud_vec[cloud_id].cloud->size(); i++) {
            point.x = mycloud_vec[cloud_id].cloud->points[i].x;
            point.y = mycloud_vec[cloud_id].cloud->points[i].y;
            point.z = mycloud_vec[cloud_id].cloud->points[i].z;
            xyzCloud->push_back(point);
        }
        if (!xyzCloud) {
            return -1;
        }

        //沟槽检测
        GrooveDetection detect;

        detect.setInputCloud(xyzCloud);

        detect.compute();

        vector<float> groove_depth(detect.groove_depth);
        vector<float> groove_width(detect.groove_width);
        vector<float> groove_length(detect.groove_length);

        // transform
        pcl::transformPointCloud(*mycloud_vec[cloud_id].cloud,
                                 *mycloud_vec[cloud_id].cloud,
                                 detect.trans2plane_matrix);
        //更新
        viewer_->updatePointCloud(mycloud_vec[cloud_id].cloud,
                                  mycloud_vec[cloud_id].cloudId);
        mycloud.cloud.reset(new PointCloudT); // Reset cloud
        mycloud.viewer = viewer_;

        //        stringstream detectResult;

        for (int i = 0; i < detect.groove_num; i++) {
            mycloud.cloud.reset(new PointCloudT);
            stringstream ss;
            ss << mycloud_vec[cloud_id].fileName << "-groove" << i + 1;
            mycloud.fileName = ss.str();
            mycloud.cloudId = "cloud-" + mycloud.fileName;
            //mycloud.isValid = true;
            pcl::copyPointCloud(*detect.grooveCloud_vec[i], *mycloud.cloud);

            mycloud.setPointColor(255, 0, 0); // red

            mycloud_vec.push_back(mycloud);
            //更新点云可视化窗口
            viewer_->addPointCloud(mycloud_vec.back().cloud, mycloud_vec.back().cloudId);

            viewer_->setPointCloudRenderingProperties(
                        pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2,
                        mycloud_vec.back().cloudId);
            viewer_->updatePointCloud(mycloud_vec.back().cloud, mycloud_vec.back().cloudId);
            viewer_->resetCamera();
            ui.screen->update();

            stringstream detectRes_s;
            detectRes_s << "depth:" << groove_depth[i] << "mm;"
                        << "width:" << groove_width[i] << "mm;"
                        << "length:" << groove_length[i] << "mm.";
            // 输出窗口
            consoleLog("GrooveDetect result", toQString(mycloud.fileName),
                       toQString(detectRes_s.str()), "");
            // cout << mycloud.fileName << endl;
            // update tree widget
            QTreeWidgetItem *cloudName =
                    new QTreeWidgetItem(QStringList() << toQString(mycloud.fileName));
            cloudName->setIcon(0, QIcon(":/Resources/images/icon.png"));
            ui.dataTree->addTopLevelItem(cloudName);

            total_points += mycloud.cloud->points.size();
        }
        ui.statusBar->showMessage("");
        //        colorCloudVecDistances();
        //        showPointcloudNew(cloud_id);
        setPropertyTable();
        // 构造了一个QTableWidget的对象，用来显示沟槽检测得到的尺寸
        QTableWidget *tableWidget = new QTableWidget(detect.groove_num, 4);
        tableWidget->setWindowTitle("沟槽尺寸");
        tableWidget->resize(600, detect.groove_num * 50); //设置表格大小
        QStringList header;
        header << "沟槽序号"
               << "深度/mm"
               << "宽度/mm"
               << "长度/mm";
        tableWidget->setHorizontalHeaderLabels(header);
        for (int i = 0; i < detect.groove_num; i++) {
            tableWidget->setItem(i, 0, new QTableWidgetItem(QString::number(i + 1)));
            tableWidget->setItem(
                        i, 1, new QTableWidgetItem(QString("%1").arg(groove_depth[i])));
            tableWidget->setItem(
                        i, 2, new QTableWidgetItem(QString("%1").arg(groove_width[i])));
            tableWidget->setItem(
                        i, 3, new QTableWidgetItem(QString("%1").arg(groove_length[i])));
        }
        // tableWidget->resizeColumnsToContents(); //列宽适应内容
        //禁止修改单元格内容
        tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
        //整行选中
        tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
        //设置为可以选中多个目标
        tableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);

        tableWidget->show();

    } else {
        //错误提示：只能选择一个点云文件
        QMessageBox::critical(this, tr("Select a part of pointcloud with mouse."),
                              tr("You can just select one Pointcloud file."));
        return -1;
    }
    return 0;
}

//划痕检测回调函数
int CloudViewer::scratchDetection(){
    QList<QTreeWidgetItem *> itemList = ui.dataTree->selectedItems();
    int selected_item_count = ui.dataTree->selectedItems().size();
    // 如果未选中任何点云，则对视图窗口中的所有点云进行着色
    if (selected_item_count == 0) {
        // 错误提示：没有选择点云文件
        QMessageBox::critical(this, tr("Select a part of pointcloud with mouse."),
                              tr("There is no Pointcloud file selected."));
        return -1;

    } else if (selected_item_count == 1) {

        int cloud_id = ui.dataTree->indexOfTopLevelItem(itemList[0]);
        pcl::PointXYZ point;
        xyzCloud.reset(new pcl::PointCloud<pcl::PointXYZ>);
        for (size_t i = 0; i < mycloud_vec[cloud_id].cloud->size(); i++) {
            point.x = mycloud_vec[cloud_id].cloud->points[i].x;
            point.y = mycloud_vec[cloud_id].cloud->points[i].y;
            point.z = mycloud_vec[cloud_id].cloud->points[i].z;
            xyzCloud->push_back(point);
        }
        if (!xyzCloud) {
            return -1;
        }

        ScratchDetection detect;

        detect.setInputCloud(xyzCloud);

        detect.compute();

        mycloud.cloud.reset(new PointCloudT); // Reset cloud
        mycloud.viewer = viewer_;
        //mycloud.isValid = true;

        mycloud.cloud.reset(new PointCloudT);
        stringstream ss;
        ss << mycloud_vec[cloud_id].fileName << "-scratch";
        mycloud.fileName = ss.str();
        mycloud.cloudId = "cloud-" + mycloud.fileName;
        pcl::copyPointCloud(*detect.scratch_cloud, *mycloud.cloud);

        mycloud.setPointColor(255, 0, 0); // red

        mycloud_vec.push_back(mycloud);
        //更新点云可视化窗口
        viewer_->addPointCloud(mycloud_vec.back().cloud, mycloud_vec.back().cloudId);

        viewer_->setPointCloudRenderingProperties(
                    pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2,
                    mycloud_vec.back().cloudId);
        viewer_->updatePointCloud(mycloud_vec.back().cloud, mycloud_vec.back().cloudId);
        viewer_->resetCamera();
        ui.screen->update();

        stringstream detectRes_s;
        detectRes_s << "depth:" << detect.scratch_depth << "mm;"
                    << "width:" << detect.scratch_width << "mm;"
                    << "length:" << detect.scratch_length << "mm.";
        // 输出窗口
        consoleLog("scratchDetect result", toQString(mycloud.fileName),
                   toQString(detectRes_s.str()), "");
        ui.statusBar->showMessage("");
        // cout << mycloud.fileName << endl;
        // update tree widget
        QTreeWidgetItem *cloudName =
                new QTreeWidgetItem(QStringList() << toQString(mycloud.fileName));
        cloudName->setIcon(0, QIcon(":/Resources/images/icon.png"));
        ui.dataTree->addTopLevelItem(cloudName);

        total_points += mycloud.cloud->points.size();

        // 构造了一个QTableWidget的对象，用来显示划痕检测得到的尺寸
        QTableWidget *tableWidget = new QTableWidget(1, 4);
        tableWidget->setWindowTitle("划痕尺寸");
        tableWidget->resize(600, 50); //设置表格大小
        QStringList header;
        header << "划痕序号"
               << "深度/mm"
               << "宽度/mm"
               << "长度/mm";
        tableWidget->setHorizontalHeaderLabels(header);
        tableWidget->setItem(0, 0, new QTableWidgetItem(QString::number(1)));
        tableWidget->setItem(
                    0, 1, new QTableWidgetItem(QString("%1").arg(detect.scratch_depth)));
        tableWidget->setItem(
                    0, 2, new QTableWidgetItem(QString("%1").arg(detect.scratch_width)));
        tableWidget->setItem(
                    0, 3, new QTableWidgetItem(QString("%1").arg(detect.scratch_length)));
        // tableWidget->resizeColumnsToContents(); //列宽适应内容
        //禁止修改单元格内容
        tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
        //整行选中
        tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
        //设置为可以选中多个目标
        tableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);

        tableWidget->show();

    } else {
        //错误提示：只能选择一个点云文件
        QMessageBox::critical(this, tr("Select a part of pointcloud with mouse."),
                              tr("You can just select one Pointcloud file."));
        return -1;
    }
    return 0;
}

//平面拟合回调函数
int CloudViewer::planFit(){
    QList<QTreeWidgetItem *> itemList = ui.dataTree->selectedItems();
    int selected_item_count = ui.dataTree->selectedItems().size();
    // 如果未选中任何点云，则对视图窗口中的所有点云进行着色
    if (selected_item_count == 0) {
        // 错误提示：没有选择点云文件
        QMessageBox::critical(this, tr("Select a part of pointcloud with mouse."),
                              tr("There is no Pointcloud file selected."));
        return -1;

    } else if (selected_item_count == 1) {

        int cloud_id = ui.dataTree->indexOfTopLevelItem(itemList[0]);
        pcl::PointXYZ point;
        xyzCloud.reset(new pcl::PointCloud<pcl::PointXYZ>);
        for (size_t i = 0; i < mycloud_vec[cloud_id].cloud->size(); i++) {
            point.x = mycloud_vec[cloud_id].cloud->points[i].x;
            point.y = mycloud_vec[cloud_id].cloud->points[i].y;
            point.z = mycloud_vec[cloud_id].cloud->points[i].z;
            xyzCloud->push_back(point);
        }
        if (!xyzCloud) {
            return -1;
        }

        PlanFit detect;

        detect.setInputCloud(xyzCloud);

        bool ok_getNormalDisThres;
        double normalDisThres = QInputDialog::getDouble(this, tr("Set plane fit normal distance weight"),
                                                        tr("normal distance weight (0~1):"), 0.3, 0, 1, 2, &ok_getNormalDisThres);
        bool ok_getPlaneDisThres;
        double planeDisThres = QInputDialog::getDouble(this, tr("Set plane fit distance threshold"),
                                                       tr("plane distance threshold (>0):"), 0.1, 0, 10, 2, &ok_getPlaneDisThres);
        if (ok_getNormalDisThres&&ok_getPlaneDisThres){
            detect.setPara(planeDisThres,normalDisThres,0.1);
        }


        detect.compute();
        //平面参数
        mycloud_vec[cloud_id].plane_A = detect.A;
        mycloud_vec[cloud_id].plane_B = detect.B;
        mycloud_vec[cloud_id].plane_C = detect.C;
        mycloud_vec[cloud_id].plane_D = detect.D;

        stringstream detectRes_s;
        detectRes_s << "(" << detect.A << ")x+("
                    << detect.B << ")y+("
                    << detect.C << ")z+("
                    << detect.D << ")=0";
        // 输出窗口
        consoleLog("Plane Fit result", toQString(mycloud_vec[cloud_id].fileName),
                   "plane coeffs:",toQString(detectRes_s.str()));

        ui.statusBar->showMessage("");

        // 构造了一个QTableWidget的对象，用来显示平面拟合的参数
        QTableWidget *tableWidget = new QTableWidget(1, 4);
        tableWidget->setWindowTitle("平面参数Ax+By+Cz+D=0");
        tableWidget->resize(600, 50); //设置表格大小
        QStringList header;
        header << "A"
               << "B"
               << "C"
               << "D";
        tableWidget->setHorizontalHeaderLabels(header);
        tableWidget->setItem(0, 0, new QTableWidgetItem(QString("%1").arg(detect.A)));
        tableWidget->setItem(
                    0, 1, new QTableWidgetItem(QString("%1").arg(detect.B)));
        tableWidget->setItem(
                    0, 2, new QTableWidgetItem(QString("%1").arg(detect.C)));
        tableWidget->setItem(
                    0, 3, new QTableWidgetItem(QString("%1").arg(detect.D)));
        // tableWidget->resizeColumnsToContents(); //列宽适应内容
        //禁止修改单元格内容
        tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
        //整行选中
        tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
        //设置为可以选中多个目标
        tableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);

        tableWidget->show();

    } else {
        //错误提示：只能选择一个点云文件
        QMessageBox::critical(this, tr("Select a part of pointcloud with mouse."),
                              tr("You can just select one Pointcloud file."));
        return -1;
    }
    return 0;
}


//高度差回调函数
int CloudViewer::heightDiff(){
    QList<QTreeWidgetItem *> itemList = ui.dataTree->selectedItems();
    int selected_item_count = ui.dataTree->selectedItems().size();
    // 如果未选中任何点云，则对视图窗口中的所有点云进行着色
    if (selected_item_count == 0) {
        // 错误提示：没有选择点云文件
        QMessageBox::critical(this, tr("Select a part of pointcloud with mouse."),
                              tr("There is no Pointcloud file selected."));
        return -1;

    } else if (selected_item_count == 2) {

        int cloud_id1 = ui.dataTree->indexOfTopLevelItem(itemList[0]);
        int cloud_id2 = ui.dataTree->indexOfTopLevelItem(itemList[1]);

        //-------------------------------平面点云1----------------------------------//
        pcl::PointXYZ point;
        xyzCloud.reset(new pcl::PointCloud<pcl::PointXYZ>);
        for (size_t i = 0; i < mycloud_vec[cloud_id1].cloud->size(); i++) {
            point.x = mycloud_vec[cloud_id1].cloud->points[i].x;
            point.y = mycloud_vec[cloud_id1].cloud->points[i].y;
            point.z = mycloud_vec[cloud_id1].cloud->points[i].z;
            xyzCloud->push_back(point);
        }
        if (!xyzCloud) {
            return -1;
        }

        bool ok_getNormalDisThres;
        double normalDisThres = QInputDialog::getDouble(this, tr("Set plane fit normal distance weight"),
                                                        tr("normal distance weight (0~1):"), 0.3, 0, 1, 2, &ok_getNormalDisThres);
        bool ok_getPlaneDisThres;
        double planeDisThres = QInputDialog::getDouble(this, tr("Set plane fit distance threshold"),
                                                       tr("plane distance threshold (>0):"), 0.1, 0, 10, 2, &ok_getPlaneDisThres);
        bool ok_getEpsAngle;
        double epsAngle = QInputDialog::getDouble(this, tr("Set epsAngle"),
                                                  tr("epsAngle(maximum allowed difference between two plane normal vectors)(>0°):"), 3.0, 0, 90, 2, &ok_getEpsAngle);


        PlanFit detect1;

        detect1.setInputCloud(xyzCloud);

        if (ok_getNormalDisThres&&ok_getPlaneDisThres){
            detect1.setPara(planeDisThres,normalDisThres,0.1);
        }


        detect1.compute();
        //平面参数
        mycloud_vec[cloud_id1].plane_A = detect1.A;
        mycloud_vec[cloud_id1].plane_B = detect1.B;
        mycloud_vec[cloud_id1].plane_C = detect1.C;
        mycloud_vec[cloud_id1].plane_D = detect1.D;

        stringstream detectRes_s1;
        detectRes_s1 << "(" << detect1.A << ")x+("
                     << detect1.B << ")y+("
                     << detect1.C << ")z+("
                     << detect1.D << ")=0";
        // 输出窗口
        consoleLog("Plane1 Fit result", toQString(mycloud_vec[cloud_id1].fileName),
                   "plane coeffs:",toQString(detectRes_s1.str()));

        ui.statusBar->showMessage("");
        //---------------------------------------------------------------------------//
        //---------------------------------平面点云2----------------------------------//
        xyzCloud.reset(new pcl::PointCloud<pcl::PointXYZ>);
        for (size_t i = 0; i < mycloud_vec[cloud_id2].cloud->size(); i++) {
            point.x = mycloud_vec[cloud_id2].cloud->points[i].x;
            point.y = mycloud_vec[cloud_id2].cloud->points[i].y;
            point.z = mycloud_vec[cloud_id2].cloud->points[i].z;
            xyzCloud->push_back(point);
        }
        if (!xyzCloud) {
            return -1;
        }

        PlanFit detect2;

        detect2.setInputCloud(xyzCloud);

        if (ok_getNormalDisThres&&ok_getPlaneDisThres){
            detect2.setPara(planeDisThres,normalDisThres,0.1);
        }
        if (ok_getEpsAngle){
            //法线约束
            detect2.setAxis(detect1.A,detect1.B,detect1.C,epsAngle);
        }

        detect2.compute();
        //平面参数
        mycloud_vec[cloud_id2].plane_A = detect2.A;
        mycloud_vec[cloud_id2].plane_B = detect2.B;
        mycloud_vec[cloud_id2].plane_C = detect2.C;
        mycloud_vec[cloud_id2].plane_D = detect2.D;

        stringstream detectRes_s2;
        detectRes_s2 << "(" << detect2.A << ")x+("
                     << detect2.B << ")y+("
                     << detect2.C << ")z+("
                     << detect2.D << ")=0";
        // 输出窗口
        consoleLog("Plane2 Fit result", toQString(mycloud_vec[cloud_id2].fileName),
                   "plane coeffs:",toQString(detectRes_s2.str()));

        ui.statusBar->showMessage("");

        //计算高度差

        float heightDiff = fabs(mycloud_vec[cloud_id1].plane_D-mycloud_vec[cloud_id2].plane_D);


        //法线v1
        Eigen::Vector3f vec1 = Eigen::Vector3f::Zero();
        vec1 << mycloud_vec[cloud_id1].plane_A, mycloud_vec[cloud_id1].plane_B, mycloud_vec[cloud_id1].plane_C;
        //法线v2
        Eigen::Vector3f vec2 = Eigen::Vector3f::Zero();
        vec2 << mycloud_vec[cloud_id2].plane_A, mycloud_vec[cloud_id2].plane_B, mycloud_vec[cloud_id2].plane_C;
        //法线夹角余弦值
        float normal_cos = fabs(vec1.dot(vec2)) / (vec1.norm()*vec2.norm());

        //高度修正
        heightDiff = heightDiff*normal_cos;

        stringstream detectRes_s;
        detectRes_s << heightDiff << "mm";
        // 输出窗口
        consoleLog("Height difference: ","",
                   toQString(detectRes_s.str()), "");

        ui.statusBar->showMessage("");

        // 构造了一个QTableWidget的对象，用来显示平面拟合的参数
        QTableWidget *tableWidget = new QTableWidget(3, 4);
        tableWidget->setWindowTitle("平面参数Ax+By+Cz+D=0");
        tableWidget->resize(600, 150); //设置表格大小
        QStringList header;
        header << "A"
               << "B"
               << "C"
               << "D";
        tableWidget->setHorizontalHeaderLabels(header);
        //平面1
        tableWidget->setItem(0, 0, new QTableWidgetItem(QString("%1").arg(detect1.A)));
        tableWidget->setItem(
                    0, 1, new QTableWidgetItem(QString("%1").arg(detect1.B)));
        tableWidget->setItem(
                    0, 2, new QTableWidgetItem(QString("%1").arg(detect1.C)));
        tableWidget->setItem(
                    0, 3, new QTableWidgetItem(QString("%1").arg(detect1.D)));
        //平面2
        tableWidget->setItem(1, 0, new QTableWidgetItem(QString("%1").arg(detect2.A)));
        tableWidget->setItem(
                    1, 1, new QTableWidgetItem(QString("%1").arg(detect2.B)));
        tableWidget->setItem(
                    1, 2, new QTableWidgetItem(QString("%1").arg(detect2.C)));
        tableWidget->setItem(
                    1, 3, new QTableWidgetItem(QString("%1").arg(detect2.D)));

        //高度差
        tableWidget->setItem(
                    2, 0, new QTableWidgetItem(QString("Height difference")));
        tableWidget->setItem(
                    2, 1, new QTableWidgetItem(QString("%1").arg(heightDiff)+"mm"));

        // tableWidget->resizeColumnsToContents(); //列宽适应内容
        //禁止修改单元格内容
        tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
        //整行选中
        tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
        //设置为可以选中多个目标
        tableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);

        tableWidget->show();

        //QMessageBox::about(this, "Result", "两个平面的高度差:"+QString::number(heightDiff)+"mm");


    } else {
        //错误提示：只能选择一个点云文件
        QMessageBox::critical(this, tr("Select a part of pointcloud with mouse."),
                              tr("You can just select two Pointcloud file."));
        return -1;
    }
    return 0;
}


//球面拟合回调函数
int CloudViewer::sphereFit(){
    QList<QTreeWidgetItem *> itemList = ui.dataTree->selectedItems();
    int selected_item_count = ui.dataTree->selectedItems().size();
    // 如果未选中任何点云，则对视图窗口中的所有点云进行着色
    if (selected_item_count == 0) {
        // 错误提示：没有选择点云文件
        QMessageBox::critical(this, tr("Select a part of pointcloud with mouse."),
                              tr("There is no Pointcloud file selected."));
        return -1;

    } else if (selected_item_count == 1) {

        int cloud_id = ui.dataTree->indexOfTopLevelItem(itemList[0]);
        pcl::PointXYZ point;
        xyzCloud.reset(new pcl::PointCloud<pcl::PointXYZ>);
        for (size_t i = 0; i < mycloud_vec[cloud_id].cloud->size(); i++) {
            point.x = mycloud_vec[cloud_id].cloud->points[i].x;
            point.y = mycloud_vec[cloud_id].cloud->points[i].y;
            point.z = mycloud_vec[cloud_id].cloud->points[i].z;
            xyzCloud->push_back(point);
        }
        if (!xyzCloud) {
            return -1;
        }

        SphereFit detect;

        detect.setInputCloud(xyzCloud);

        detect.compute();

        //球面直径
        stringstream detectRes_s;
        detectRes_s << detect.diameter << "mm";
        // 输出窗口
        consoleLog("Height Diff result",toQString(mycloud_vec[cloud_id].fileName),
                   toQString(detectRes_s.str()), "");

        ui.statusBar->showMessage("");

        QMessageBox::about(this, "Result", "球面直径:"+QString::number(detect.diameter)+"mm");



    } else {
        //错误提示：只能选择一个点云文件
        QMessageBox::critical(this, tr("Select a part of pointcloud with mouse."),
                              tr("You can just select one Pointcloud file."));
        return -1;
    }
    return 0;
}
